<?php
/**
 * Created by PhpStorm.
 * User: ivi
 * Date: 2019/2/19
 * Time: 22:25
 */

namespace App\Repositories\System;

use App\Exceptions\SysException;
use App\Facade\AppContext;
use App\Facade\System\File;
use App\Facade\System\Role;
use App\Models\BaseModel;
use App\Models\System\Group;
use App\Models\System\User;
use App\Repositories\BaseRepository;
use App\Traits\RequestCache;
use App\Utils\Baidu;
use App\Utils\Output;
use App\Utils\Pager;
use App\Utils\QueryHelper;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use Throwable;

/**
 * 系统用户
 * Class SystemUserRepository
 * @package App\Repositories
 */
class UserRepository extends BaseRepository
{
    use RequestCache;

    function getName($id)
    {
        return $this->requestCache('name_' . $id, function () use ($id) {
            $user = User::query()->find($id);
            if (empty($user)) {
                return '';
            }

            if (empty($user['name'])) {
                $value = $user['username'];
            } else {
                $value = $user['name'];
            }
            if (!empty($user['mobile'])) {
                $value .= "({$user['mobile']})";
            }
            return $value;
        });
    }

    function findByEmail($email)
    {
        return User::query()->where('email', '=', $email)->first();
    }

    function changeSkin($id, $skin)
    {
        User::query()->where('id', '=', $id)->update(['skin' => $skin]);
    }

    /**
     * @param array $ids
     * @throws SysException
     */
    function deleteAfter(array $ids)
    {
        if (in_array(1, $ids)) {
            throw new SysException(__('common.tips.can_not_delete_super_administrator'));
        }
    }

    /**
     * @param $id
     * @param $status
     * @return Output
     */
    function changeStatus($id, $status): Output
    {
        if ($id == 1) {
            return Output::fail(__('common.tips.super_administrator_status_cannot_be_modified'));
        }
        $entity = User::find($id);
        if ($entity && $entity->type == 1) {

            $entity['status'] = $status == 1 ? 1 : 2;
            $entity->save();
            return Output::success(__('common.tips.operation_successful'));
        }
        return Output::fail(__('common.tips.data_does_not_exist'));
    }

    /**
     * @param $id
     * @return Output
     */
    function editInfo($id): Output
    {
        $entity = User::find($id);
        if ($entity) {
            unset($entity['password']);
            if (!empty($entity['hospital_ids'])) {
                $entity['hospital_ids'] = explode(',', $entity['hospital_ids']);
            } else {
                $entity['hospital_ids'] = [];
            }
            return Output::data($entity);
        }
        return Output::fail(__('common.tips.data_does_not_exist'));
    }

    /**
     * @param array $data
     * @param int $id
     * @return Output
     */
    function save($data, $id = 0): Output
    {
        $password = Arr::get($data, 'password');
        unset($data['password']);
        if ($id) {
            $entity = User::find($id);
            if (empty($entity || $entity->type != 1)) {
                return Output::fail(__('common.tips.data_does_not_exist'));
            }
        } else {
            $entity = new User();
        }
        $entity->fill($data);
        if (!$id) {
            return $this->_setPassword($entity, $password);
        } else {

            if (!empty($password)) {
                $this->_setPassword($entity, $password);
            } else {
                $entity->save();
            }

        }
        return Output::data($entity, __('common.tips.operation_successful'));
    }

    /**
     * @param $id
     * @param $old
     * @param $pass
     * @return Output
     */
    function changePassword($id, $old, $pass): Output
    {
        $userInfo = User::find($id);
        if ($userInfo || $userInfo->type != 1) {
            if ($userInfo->password == $this->_buildPassword($old, $userInfo->salt)) {
                $this->_setPassword($userInfo, $pass);
                return Output::success('修改成功');
            } else {
                return Output::fail('密码错误！');
            }
        }
        return Output::fail('用户不存在！');
    }

    /**
     * @param User $userInfo
     * @param $pass
     * @return Output
     */
    function _setPassword($userInfo, $pass)
    {
        $userInfo->salt = Str::random(4);
        $userInfo->password = $this->_buildPassword($pass, $userInfo->salt);
        $userInfo->save();
        return Output::data($userInfo, __('common.tips.operation_successful'));
    }

    function setPassword($id, $pass): Output
    {
        $userInfo = User::find($id);
        if ($userInfo) {
            return $this->_setPassword($userInfo, $pass);
        }
        return Output::fail('用户不存在！');
    }

    function recharge($id, $money): Output
    {
        try {
            DB::beginTransaction();
            $user = User::find($id);
            if (empty($user)) {
                throw new SysException('用户不存在');
            }
            $log = [
                'user_id' => $id,
                'operator_id' => AppContext::userId(),
                'before_balance' => $user['balance'],
                'desc' => '充值 ' . $money . '元',
                'money' => $money
            ];
            //扣掉余额
            $user->balance = round($user->balance + $money);
            $user->save();
            $log['after_balance'] = $user->balance;
            UserBalanceLog::create($log);
            DB::commit();
            return Output::success();
        } catch (Throwable $e) {
            DB::rollBack();
            return Output::error($e, '充值失败');
        }
    }

    private function _buildPassword($pass, $salt): string
    {
        return md5(md5($pass) . $salt);
    }

    function login($username, $password, $group_code = ''): Output
    {
        $query = User::query()
            ->where(function ($query) use ($username) {
                $query->where('username', '=', $username);
                $query->whereNull('deleted_at');
                $query->orWhere('mobile', '=', $username);
            });
        if (!empty($group_code)) {
            if (is_array($group_code)) {
                $query->whereIn('group_code', $group_code);
            } else {
                $query->where('group_code', '=', $group_code);
            }
        }
        $userInfo = $query->first();
        if ($userInfo) {
            if ($userInfo->status != 1) {
                return Output::fail('账号已被冻结！');
            }
            if ($userInfo->password == $this->_buildPassword($password, $userInfo->salt)) {
                unset($userInfo->salt);
                unset($userInfo->password);
                return Output::data($userInfo->toArray());
            } else {
                return Output::fail(__('system.user.tips.wrong_password'));
            }
        }
        return Output::fail(__('system.user.tips.user_does_not_exist'));
    }


    function apiLogin($mobile, $groupCodes = [])
    {
        $query = User::query()
            ->where('mobile', '=', $mobile);
        if (!empty($groupCodes)) {
            $query->whereIn('group_code', $groupCodes);
        }
        $userInfo = $query->first();
        if ($userInfo) {
            unset($userInfo['password']);
            unset($userInfo['salt']);
            return Output::data($userInfo);
        }
        return Output::fail('用户不存在！');
    }

    function apiUserInfo($id)
    {
        if (is_numeric($id)) {
            $userInfo = User::find($id);
        } else {
            $userInfo = $id;
        }
        $result = [
            'mobile' => $userInfo['mobile'],
            'name' => $userInfo['name'],
            'group_code' => $userInfo['group_code'],
            'avatar_id' => $userInfo['avatar_id'],
            'avatar_url' => $userInfo['avatar_id'] > 0 ? File::image($userInfo['avatar_id']) : "",
            'token' => AppContext::getToken(),
            'id' => $userInfo['id'],
        ];
        return Output::data($result);
    }

    function adminPager($params)
    {
        extract($params);
        $query = User::query();
        if (!empty($keyword)) {
            QueryHelper::like($query, 'system__users.username|system__users.name|system__users.mobile', $keyword);
        }
        if (!empty($start)) {
            $query->where('system__users.created_at', '>=', strtotime($start));
        }
        if (!empty($end)) {
            $query->where('system__users.created_at', '<=', strtotime($end . ' 23:59:59'));
        }
        if (!empty($role_id)) {
            $query->where('system__users.role_id', '=', $role_id);
        }
        if (!empty($group)) {
            $query->where('system__users.group_code', '=', $group);
        }
        $total = $query->count();
        $query->leftJoin('system__roles', 'system__roles.id', 'system__users.role_id');
        $query->select(
            'system__users.id',
            'system__users.username',
            'system__roles.name as role_name',
            'system__users.email',
            'system__users.group_code',
            'system__users.created_at',
        );
        $lis = Pager::setPageParams($query, $params)->get();
        return Output::pager($lis, $total);
    }

    /**
     * @param $params
     * @return Output
     */
    function choosePager($params)
    {
        extract($params);
        $query = User::query();
        if (!empty($keyword)) {
            QueryHelper::like($query, 'system__users.username|system__users.name|system__users.mobile', $keyword);
        }
        if (!empty($start)) {
            $query->where('system__users.created_at', '>=', strtotime($start));
        }
        if (!empty($end)) {
            $query->where('system__users.created_at', '<=', strtotime($end . ' 23:59:59'));
        }
        if (!empty($role_id)) {
            $query->where('system__users.role_id', '=', $role_id);
        }
        if (!empty($group)) {
            $query->where('system__users.group_code', '=', $group);
        }

        $total = $query->count();
        $query->leftJoin('system__roles', 'system__roles.id', 'system__users.role_id');
        $query->select(
            'system__users.id',
            'system__users.username',
            'system__roles.name as role_name',
            'system__users.name',
            'system__users.mobile',
            'system__users.email',
            'system__users.updated_at'
        );
        $lis = Pager::setPageParams($query, $params)->get();
        return Output::pager($lis, $total);
    }

    /**
     *
     * @param $data
     * @return Output
     */
    function apiRegister($data)
    {
        try {
            DB::beginTransaction();
            if ($data['identity'] == 1) {
                $data['group_code'] = Group::STUDENT;
                $data['role_id'] = Role::default(Group::STUDENT);
                $educational_experience = Arr::get($data, 'educational_experience', '');
                if (!empty($educational_experience)) {
                    $educational_experiences = json_decode($educational_experience, true);
                    $highest_education = 0;
                    foreach ($educational_experiences as $experience) {
                        if ($experience['education'] > $highest_education) {
                            $highest_education = $experience['education'];
                            $data['highest_education'] = $highest_education;
                            if (isset($experience['school_id'])) {
                                $data['school_id'] = $experience['school_id'];
                            }
                        }
                    }
                } else {
                    throw new SysException(__('system.user.validation.school_id.required'));
                }
            } else {
                $data['group_code'] = Group::STAFF;
                $data['role_id'] = Role::default(Group::STAFF);
                $company_id = Arr::get($data, 'company_id', 0);
                if (empty($company_id)) {
                    //添加公司
                    $company = Arr::get($data, 'company', '');
                    if (!empty($company)) {
                        $company = json_decode($company, true);
                        $company['license_id'] = $data['license_id'];
                    } else {
                        throw new SysException(__('system.user.tips.please_fill_in_the_company_information'));
                    }
                    //解析坐标
                    try {
                        list($company['lat'], $company['lng']) = Baidu::geocoding($company['address']);
                    } catch (Throwable $throwable) {
                        //坐标解析失败
                        $company['lat'] = 0;
                        $company['lng'] = 0;
                    }
                    $company['status'] = 1;
                    $companyResult = \App\Facade\Job\Company::create($company);
                    if ($companyResult->isSuccess()) {
                        $company_id = $data['company_id'] = $companyResult->data;
                    } else {
                        throw new SysException($companyResult->msg);
                    }
                }
            }
            $user = User::create($data);
            $data['user_id'] = $user['id'];
            if ($data['identity'] == 1) {
                Resume::create($data);
            }
            DB::commit();
            return Output::data($user);
        } catch (Throwable $throwable) {
            DB::rollBack();
            return Output::error($throwable, '用户注册');
        }
    }

    function apiSimpleStaff($id)
    {
        $user = User::where('id', '=', $id)->withTrashed()->first();
        return [
            'id' => $user['id'],
            'name' => $user['name'],
            'mobile' => $user['mobile'],
            'post' => $user['post'],
            'avatar_url' => File::image($user['avatar_id'])
        ];
    }

    function getModel(): BaseModel
    {
        return new User();
    }
}
